[VisualEffectGraph-Samples を読む] ①ElectricityEffect

October 30, 2022


モデルが発する帯電エフェクト

568C2D82755D1CC933680CF55E557D66

左上のSpawn

左の処理シーケンスから見ていきます 0B8DFF7397B5BB18BF042FBDB821DEB1

Spawn内の各ノードの説明

① Constant Spawn Rate 指定した数のパーティクルを1秒に生成されるような生成処理を行う → 1秒に一回生成するのではなく。毎フレームdeltaTimeに応じて生成しているため一秒にrate数分生成されるということ

② Periodic Burst (定期的) ※ 後述のSingle Burstの Repeatを Periodic に変更するとノード名が変化します 定期的にパーティクルの数を生成。 瞬間的に生成する。 Delayで指定した時間待機(秒)。経過後次のパーティクルを生成

■ Spawn Mode

  • Constant
    • 固定数を生成
  • Random
    • X~Y間のランダム

■ Delay Mode

  • Constant
    • 固定秒数待機
  • Random
    • X~Y間のランダム

③ Single Burst 一度だけ瞬間的に生成

その他 Set SpawnEvent Lifetime Lifetimeを動的に変更する これは Initialize にある Iherit Source Liefetime が利用しています。つまりSpawnに設定されている値を利用してパーティクルの生存期間を指定。 80F589CBBE97CA2FA4273B3E73E47AD2

右の Single Burst は 0.3 が指定されているため、ここで生成されたパーティクルは左のSpawnよりも 0.1秒寿命が短いということになります

Update

44F1BAE5F55EFDA7A1056B2F0722C348

Update部分は長いですがひとつひとつ見ていきます。上から順番

A1E3455AE12041B35ABD62DC85EEB49E

まずよく見ると右上が WORLD となっています。 ここは Space を変更する箇所で、クリックするたびに Local ↔ World と変化します(わかりにくい)

Space

Localの場合は親オブジェクトのローカル座標で動かすことになり、親が動くとパーティクルも動く Worldの場合は放出されたパーティクルは親に追従しません

① SetPosition

左端にずずっ..とスクロール 845345B78AC1793919230AA8BC6D0A0C

① SkinndMeshRendererプロパティをGet

② SkinndMeshRendererから頂点数を取得

③、④ RundomNumberは [Min-Max] 間のランダム値を返すものでそれぞれ [0-②] [②-1] の数を獲得。 設定は PerParticle となっており、パーティクル毎にランダムな値が返されます

ランダムで求めた値を Sample Skinned Mesh に接続

Sample Mesh

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@12.1/manual/Operator-SampleMesh.html 引数の SkinnedMesh の頂点から Position, Color, TexCoord0, Normal,,, などなど 情報を返却してくれるありがたいノードです 3307BA8F5AF190E1C96ABF926778BACE

Vertexに値が設定されている頂点をサンプリングします。今回はランダムの出力値を設定しているため、ランダムな頂点をサンプリングします

Positionが右に伸び、 Position と繋がり、そのPositionのベクトル座標に固定値を Add しているノードが存在

8EDCD90008C8DE1590FDEE99227A0EDA

Position を Position につなげているのが疑問ですが、よくみると W と書かれているのがわかります これは座標をワールドSpaceに変換していることを表しているものと思われます

その値に対し補正用に固定値をAddし、最終的に Sample Bezier に接続 08611090C0D1D79903CB366A36272CB4

Sample Bezier

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@12.1/manual/Operator-SampleBezier.html ベジェ曲線を生成するノードとなり、4つの点と現在の進行状況を表す t で曲線を求めます

↓ 公式動画

t は Age Over Lifetime が接続されています

Age Over Lifetime

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@12.1/manual/Operator-AgeOverLifetime.html

パーティクルの残り寿命を [0-1] 範囲に収めて返すノードですね つまり、生まれたてはAに近く、死にかけはDの点に近くなります。

この曲線で電撃が体にはっているような演出を表していました。

つまり①のSetPositionが行っていたことは

  • パーティクルのモデルの頂点をランダムに選出
  • ワールド座標系のPositionを抽出
  • 2点間を直線ではなく曲線で書くことで電撃感が出る位置を求めている

ということでした

② SetPosition

①もSetPosition,②もSetPosition。やってることはシンプルで A40FD4087DEB7938FF365FD5560D0BDC

Get Attribute: position [Current] は①で求めた座標を取得しています。 RootTransform はプロパティでうけとる Transform の Posotion です。 TransformのPositionに対して①のPositionを足し合わせて補正しています。

公式の説明がわかりやすい https://docs.unity3d.com/ja/Packages/com.unity.visualeffectgraph@10.7/manual/Operator-Transform(Position).html

RootTransformはVFXPropertyBinderで、モデルのHip(モデルの中心点となる箇所)が指定されており、 エフェクトとモデルのズレを矯正してくれています(このスクリプトを消して実行してみると変化がわかりやすい) E42D41063B62993BAB2AA746BF86A169

③ Set Alive

Alive プロパティの設定。 Aliveのチェックを外すとそのパーティクルは即死します

965470D377D995EA0D2042E48280FA7B

モデルに合わせたマスクテクスチャを利用していました こちらを始点と終点のUVでサンプリングして、 Compare ノードで比較。 Greater が設定されているため Left (サンプリング側) が 0.85 より大きければ 1 を返します。 その双方を And でビット演算した結果を Set Aliveに利用しています

つまり、どちらも 0.85以上の出力をしている場合は問題なくパーティクルを生成しますが、それ以外はパーティクルを発生させません マスクを見ると F441DCC52DF118449623BF3E903DB072

目や鼻、口などの部分には色が乗っておらず、電撃ポイントの対象外としているようです

続いて、これらの結果を GPU Event で別の処理に移行しています B42F09D38900DC22D7042C3AF71F92E7

このように処理を別に書きたい場合に GPU Event で前シーケンスの結果を利用する形を取っています

まずはIntializeをみます。 ブロックは Initialize Particle Strip ノードとなっています。

Particle Strip は公式の動画がとてもわかり易いです https://www.youtube.com/watch?v=gdb9zvHh3r0

画像で一発で説明すると EA51ECE724920DEB0991EB8F227D6971 こういう事が可能になるようです つまり、生成したパーティクルの動きを線でつなげて帯状に描画することが可能になる。

なので、まずはUpdateで動きを表し、次のシーケンスでそれらをつなげて帯として描画する。という二段階の処理を構築されています

これで雷の帯を表しています 内に持っているノードは

  • Inherit Source Position (Set)
    • 前の結果の座標を利用する
  • Set Liefetime
    • 生存時間

です。

そして次のブロック、Update Particle Strip は Turbulence ノードがついています 6EFD5D137824BB4E94DC07B2601A9A91

こちらも公式の説明がわかりやすいです https://docs.unity3d.com/ja/Packages/com.unity.visualeffectgraph@10.7/manual/Block-Turbulence.html

速度に合わせて乱流を生むノードとなっており、動きをつけるときにとても重宝するノード 今回は雷の動きのゆらぎに利用されています

最後は Output ParticleStrip Quad

5EA9E4729EFA0B9639E4CF5E29745C67

こちらはノードがいくつかひっついています

Orient: Face Camera Position

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@12.1/manual/Block-Orient.html 公式によると Face Camera Posotion は常にカメラ方向にパーティクルを向けるようにします

Subpixel Anti-Aliasing

https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@12.1/manual/Block-SubpixelAntiAliasing.html

画像で見るとわかりやすいですが 4E8F4F30ACB3AEFA31FA7E1F34BCD120

パーティクルの角度、拡縮によってパーティクルが見えなくならないように補正をしてくれるノードのようです ON/OFFで違いを見ればわかりやすく、OFFにすると帯状のエフェクトの中が途切れるのが確認できます

Set Size over Life

生存時間に応じてパーティクルのサイズをカーブで制御

SetColor

色の設定

Set Alpha over Life 生存期間に応じてパーティクルのサイズをカーブで制御

以上で左側の処理を見ていけました 続いて右側の処理を見ていきます

Spawn

まずはSpawn郡

A34919E729CAEBBA825C933C276C96C1

periodic Burst, SIngle Burstは前回と同じで 真ん中のSpawnに Loop Duration と Loop Count が設定されています

Loop Duration でループ間隔、 Loop Count でループ回数

Iniialize

65CC06083CF9272C2AC9FF16FF2108F8

上のブロックから見ていきます

①Set Position 同じくSkinnedMeshRendererの頂点数を RandomNumber [0-VertexCount] でランダム頂点を取り出し、 Position を設定しています

②Set Postiion ①のSetPostiionで設定したPositionとプロパティTrasnfromのPositionを足し合わせています

③Set Velocity Random(Per-component) パーティクルの速度をランダムに設定

③ Set LIefetime Ranfom (Uniform) 生存時間をランダムに決定

上記ランダムの Per-component, Uniform については公式の動画で詳細が説明されています https://learning.unity3d.jp/6582/

BD78703672D469D093E59B7BF9C9091E

最後に描画処理のOutputでうが、特に変わったことは無くそのまま表示しています 0C074BE2F74BF4D70F31CE41C4B77C5E

以上でモデルを這う雷の表現のサンプルでした こちらのエフェクトは視覚的にもインパクトが有り使いやすそうです